home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / DNet / DURL.cpp < prev    next >
Text File  |  1996-07-05  |  11KB  |  425 lines

  1. // DURL
  2. // d.g.gilbert, Sep.94
  3.  
  4. #include <ncbi.h>
  5. #include <dgg.h>
  6.  
  7. #include <DFile.h>
  8. #include "DTCP.h"
  9. #include "DNetObject.h"
  10. #include "DGoClasses.h"
  11. #include "DURL.h"
  12.  
  13.  
  14.  
  15.  
  16. // DURL ------------------------------
  17.  
  18.  
  19. DURL::DURL()
  20. {
  21. }
  22.  
  23.  
  24. short DURL::IsURL( const char *line, char*& url, long maxline)
  25. {    // adapated from Lynx
  26.   char *cp, *lineend;
  27.     
  28.   // don't crash on an empty argument 
  29.   if (line == NULL || *line == '\0') return(DNetOb::kUnknownProt);
  30.     if (maxline) lineend = (char*)line + maxline;
  31.     else lineend= StrChr( (char*)line,'\0');
  32.     
  33.     
  34.     /// god damn over duplication -- combine this w/ NetOb's list of protos
  35.     
  36.     
  37.     for (cp= (char*)line; cp < lineend && *cp!= ':'; cp++) ;
  38.     if (*cp != ':') { url= (char*)line; return(DNetOb::kUnknownProt); }
  39.     else if (cp[1] != '/' && cp[2] != '/') {
  40.       // these are only ones that don't contain "://"  
  41.       if (!Nlm_StrNICmp( (url=cp-4),"news",4))                    return(DNetOb::kNNTPprot);
  42.       else if (!Nlm_StrNICmp( (url=cp-6),"mailto",6))        return(DNetOb::kSMTPprot);
  43.       else if (!Nlm_StrNICmp( (url=cp-5),"whois",5))        return(DNetOb::kWhoisprot);
  44.       else if (!Nlm_StrNICmp( (url=cp-6),"finger",6))        return(DNetOb::kFingerprot);
  45.       else if (!Nlm_StrNICmp( (url=cp-4),"nntp",4))            return(DNetOb::kNNTPprot);
  46.       else if (!Nlm_StrNICmp( (url=cp-9),"newspost",8))    return(DNetOb::kUnsupportedProt);
  47.         else     {  
  48.           while (cp>line && isalpha(cp[-1])) cp--;
  49.           url= cp;
  50.           return(DNetOb::kUnknownProt); 
  51.           }
  52.         }
  53.  
  54.   else if (!Nlm_StrNICmp( (url=cp-6),"gopher",6))        return(DNetOb::kGopherprot);
  55.   else if (!Nlm_StrNICmp( (url=cp-4),"http",4))            return(DNetOb::kHTTPprot);
  56.   else if (!Nlm_StrNICmp( (url=cp-3),"bop",3))            return(DNetOb::kBOPprot);
  57.   else if (!Nlm_StrNICmp( (url=cp-3),"pop",3))            return(DNetOb::kPOPprot);
  58.   else if (!Nlm_StrNICmp( (url=cp-3),"ftp",3))             return(DNetOb::kFTPprot);
  59.   else if (!Nlm_StrNICmp( (url=cp-4),"file",4))             return(DNetOb::kFileprot);
  60.   else if (!Nlm_StrNICmp( (url=cp-4),"wais",4))             return(DNetOb::kWAISprot);
  61.   else if (!Nlm_StrNICmp( (url=cp-6),"telnet",6))        return(DNetOb::kTelnetprot);
  62.   else if (!Nlm_StrNICmp( (url=cp-6),"tn3270",6))        return(DNetOb::kTN3270prot);
  63.   else if (!Nlm_StrNICmp( (url=cp-6),"rlogin",6))         return(DNetOb::kUnsupportedProt);
  64.   else if (!Nlm_StrNICmp( (url=cp-3),"afs",3))             return(DNetOb::kUnsupportedProt);
  65.   else if (!Nlm_StrNICmp( (url=cp-8),"prospero",8))    return(DNetOb::kUnsupportedProt);
  66.         // !! Need also to support User-Added protocols via Type/Handler method !
  67.   else    { 
  68.       while (cp>line && isalpha(cp[-1])) cp--;
  69.       url= cp;
  70.       return(DNetOb::kUnknownProt); 
  71.       }
  72. }
  73.  
  74.  
  75.  
  76. // from Lynx
  77.  
  78. /*        Escape undesirable characters using %        HTEscape()
  79. **        -------------------------------------
  80. **
  81. **    This function takes a pointer to a string in which
  82. **    some characters may be unacceptable unescaped.
  83. **    It returns a string which has these characters
  84. **    represented by a '%' character followed by two hex digits.
  85. **
  86. **    In the tradition of being conservative in what you do and liberal
  87. **    in what you accept, we encode some characters which in fact are
  88. **    allowed in URLs unencoded -- so DON'T use the table below for
  89. **    parsing! 
  90. **
  91. **    Unlike HTUnEscape(), this routine returns a malloced string.
  92. **
  93. */
  94.  
  95.     
  96. static unsigned char isAcceptable[96] =
  97. /* Overencodes */
  98. /*    Bit 0        alphaChars        -- see HTFile.h
  99. **    Bit 1        alphaPlusChars -- as alphaChars but with plus.
  100. **    Bit 2 ...    pathChars        -- as alphaPlusChars but with /
  101. */
  102. /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
  103. {  0,0,0,0,0,0,0,0,0,0,7,6,0,7,7,4,    /* 2x   !"#$%&'()*+,-./     */
  104.      7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,    /* 3x  0123456789:;<=>?     */
  105.      7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,    /* 4x  @ABCDEFGHIJKLMNO  */
  106.      7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,    /* 5X  PQRSTUVWXYZ[\]^_     */
  107.      0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,    /* 6x  `abcdefghijklmno     */
  108.      7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0 };    /* 7X  pqrstuvwxyz{\}~    DEL */
  109.  
  110. #define OKAYCHAR(a,mask)    ( a>=32 && a<128 && ((isAcceptable[a-32]) & mask))
  111.  
  112. char* DURL::EncodeChars( const char* str, unsigned char mask)
  113. {
  114.     static char *hexchars = "0123456789ABCDEF";
  115.   const char * p;
  116.   char * q;
  117.   char * result;
  118.   int unacceptable = 0;
  119.  
  120.   for (p=str; *p; p++)
  121.          if (!OKAYCHAR( (unsigned char)*p, mask)) 
  122.             unacceptable++;
  123.   result = (char *) MemNew( p - str + unacceptable + unacceptable + 1);
  124.   if (result == NULL) return "";
  125.  
  126.   for (q=result, p=str; *p; p++) {
  127.       unsigned char a = *p;
  128.         if (!OKAYCHAR(a, mask)) {
  129.         *q++ = HEX_ESCAPE;    
  130.         *q++ = hexchars[a >> 4];
  131.         *q++ = hexchars[a & 15];
  132.             }
  133.         else *q++ = *p;
  134.       }
  135.   *q++ = 0;            
  136.   return result;
  137. }
  138.  
  139.  
  140. /*        Decode %xx escaped characters            HTUnEscape()
  141. **        -----------------------------
  142. **
  143. **    This function takes a pointer to a string in which some
  144. **    characters may have been encoded in %xy form, where xy is
  145. **    the acsii hex code for character 16x+y.
  146. **    The string is converted in place, as it will never grow.
  147. */
  148.  
  149. static char from_hex(char c)
  150. {
  151.     return  c >= '0' && c <= '9' ?  c - '0' 
  152.             : c >= 'A' && c <= 'F'? c - 'A' + 10
  153.             : c - 'a' + 10;     
  154. }
  155.  
  156. //static
  157. char* DURL::DecodeChars( char * str)
  158. {
  159.   char * p = str;
  160.   char * q = str;
  161.  
  162.   if (!str) return "";
  163.   while(*p) {
  164.        if (*p == HEX_ESCAPE) {
  165.         p++;
  166.         if (*p) *q  = from_hex(*p++) * 16;
  167.          if (*p) *q += from_hex(*p++);
  168.       q++;
  169.             } 
  170.    else 
  171.         *q++ = *p++; 
  172.      }
  173.   *q++ = 0;
  174.   return str;
  175.  
  176.  
  177. char* DURL::GetParts( const char* url, long whichparts, long urlsize)
  178. {
  179.     char *cp, *ep, sep, *newurl, *line, *newline;
  180.     
  181.   if (url == NULL || *url == '\0') return NULL;
  182.     if (!urlsize) urlsize= StrLen(url);
  183.     line= (char*) Nlm_MemNew(urlsize+1);
  184.     Nlm_MemCopy(line, url, urlsize);
  185.   line[urlsize]= 0;
  186.     newline= (char*) Nlm_MemNew(urlsize+1);
  187.   *newline= 0;
  188.   
  189.     long prot= IsURL( line, newurl);
  190.     cp= newurl;
  191.     ep= StrChr( newurl+3, ':');
  192.     if (ep) ep++;
  193.     if (*ep == '/') ep++;
  194.     if (*ep == '/') ep++;
  195.     if (whichparts & kPartProtocol) {
  196.         sep= *ep; *ep= 0;
  197.         StrCat( newline, cp);
  198.         *ep= sep;
  199.         }
  200.     cp= ep;
  201.     
  202.     while (isspace(*cp)) cp++;
  203.     ep= cp;
  204.     while ( *ep && (OKAYCHAR(*ep, alphaPlusChars)) ) ep++;
  205.     //while (*ep && (isalnum(*ep) || *ep == '.')) ep++;
  206.     while (isspace(*ep)) ep++;
  207.     if (whichparts & kPartHost) {
  208.         sep= *ep; *ep= 0;
  209.         StrCat( newline, cp);        
  210.         *ep= sep;
  211.         }
  212.     cp= ep;  
  213.  
  214.     if (*cp == ':') {    // port num
  215.         ep = cp + 1;
  216.         while (isspace(*ep)) ep++;
  217.         while (isdigit(*ep)) ep++;
  218.         if (whichparts & kPartPort) {
  219.             sep= *ep; *ep= 0;
  220.             StrCat( newline, cp);        
  221.             *ep= sep;
  222.             }
  223.         cp= ep;  
  224.         }        
  225.     while (isspace(*cp)) cp++;
  226.  
  227.     if (*newline && *cp == '/') {
  228.         StrCat( newline, "/");        
  229.         }
  230.         
  231.     if (whichparts & kPartPath) {
  232.         if (*cp == '/') cp++;
  233.         StrCat( newline, cp);        
  234.         }
  235.  
  236.     MemFree( line);
  237.     return newline;
  238. }
  239.  
  240.  
  241.  
  242. Boolean DURL::ParseURL( DNetOb* nob, const char *url, long urlsize, Boolean verbatim)
  243. {
  244.   char *cp, *ep, *qp, sep, *line, *newurl;
  245.     short prot;
  246.     Boolean isLocalhost;
  247.     
  248.   if (!nob || url == NULL || *url == '\0') return false;
  249.   if (!urlsize) urlsize= StrLen(url);
  250.  
  251.       // can we do this space check safely?
  252.   newurl= (char*)url;  while (isspace(*newurl)) { newurl++; urlsize--; }
  253.   ep= newurl + urlsize - 1;  while (isspace(*ep)) { ep--; urlsize--; }
  254.   
  255.     line= (char*) Nlm_MemNew(urlsize+1);
  256.     Nlm_MemCopy(line, newurl, urlsize);
  257.   line[urlsize]= 0;
  258.     prot= IsURL( line, newurl);
  259.     if (prot <= DNetOb::kUnknownProt) {
  260.         MemFree( line);
  261.         return false;
  262.         }
  263.     else {
  264.         // need to drop "", '', <> or other delimiters from url end
  265.         // also filter out newlines, controls, and spaces unless "" or ''
  266.         {
  267.             cp= newurl;
  268.             if (cp>line) do { cp--; } while (cp>line && !isgraph(*cp));
  269.             ep= cp;
  270.             switch (*cp) {
  271.                 case '"': 
  272.                     newurl= cp+1;  
  273.                     do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='"');
  274.                     *ep= 0;
  275.                     break;
  276.                 case '\'':
  277.                     newurl= cp+1;  
  278.                     do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='\'');
  279.                     *ep= 0;
  280.                     break;
  281.                 case '<':
  282.                     newurl= cp+1; 
  283.                     if (verbatim)
  284.                         do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='>');
  285.                     else 
  286.                         do { if (isgraph(*cp)) *ep++= *cp; cp++; } while (*cp && *cp!='>');
  287.                     *ep= 0;
  288.                     break;
  289.                 default:
  290.                     newurl= cp;  
  291.                     if (verbatim)
  292.                         do { if (isprint(*cp)) *ep++= *cp; cp++; } while (*cp);
  293.                     else 
  294.                         do { if (isgraph(*cp)) *ep++= *cp; cp++; } while (*cp);
  295.                     *ep= 0;
  296.                     break;
  297.                 }
  298.             }
  299.         nob->StoreProtocol( prot);
  300.          nob->StoreURL(newurl);
  301.         cp= StrChr(newurl+3,':');
  302.         cp++;
  303.         if (*cp == '/') cp++;
  304.         if (*cp == '/') cp++;
  305.         while (isspace(*cp)) cp++;
  306.         if (prot == DNetOb::kSMTPprot) {
  307.             DecodeChars(cp);
  308.             nob->fType= kMailType; // mailto gopher kind  
  309.             nob->StorePath(cp);
  310.             MemFree( line);
  311.             return true;
  312.             }
  313.             
  314.         ep= cp;
  315.         while ( *ep && (OKAYCHAR(*ep, alphaPlusChars)) ) ep++;
  316.         //while (*ep && (isalnum(*ep) || *ep == '.' || *ep == '-')) ep++;
  317.  
  318.          while (isspace(*ep)) ep++;
  319.         sep= *ep; *ep= 0;
  320.         isLocalhost = (ep - cp < 2); // || StrICmp( cp, "localhost")==0 );
  321.         nob->StoreHost( cp);    
  322.         *ep= sep;
  323.         cp= ep; // NO: +1;
  324.  
  325.         if (sep == ':') {    // port num
  326.             ep= ++cp;
  327.             while (isspace(*ep)) ep++;
  328.             while (isdigit(*ep)) ep++;
  329.             sep= *ep; *ep= 0;
  330.             nob->StorePort( cp);    
  331.             *ep= sep;
  332.             cp= ep; //+1;
  333.             }        
  334.         if (sep == '/') ;
  335.         while (isspace(*cp)) cp++;
  336.  
  337.         qp= StrChr(cp, '?');
  338.         if (qp) {
  339.             *qp++= 0;
  340.             nob->fQueryGiven= StrDup(qp);
  341.             }
  342.             
  343.         DecodeChars(cp);    // ???
  344.  
  345.         switch (prot) {
  346.             case DNetOb::kGopherprot: // gopher://host.name:70/00/path/to/data
  347.                 if (*cp) cp++;
  348.                 if (*cp == 0) {
  349.                     nob->fType= kTypeFolder;  
  350.                     nob->StorePath(""); 
  351.                     }
  352.                 else {
  353.                     nob->fType= *cp;  
  354.                     nob->StorePath( cp+1); 
  355.                     }
  356.                 break;
  357.                 
  358.             case DNetOb::kFTPprot: // file:///path:to:file
  359.             case DNetOb::kFileprot: // file:///path:to:file
  360.                 if (*cp == '/') {          
  361.                         // this leading slash is artifact of silly url syntax !!
  362.                         // skip for all????? but sometimes (non-local) this is valid
  363. #if 1
  364.                     if (isLocalhost) cp++;
  365. #else
  366. #ifdef OS_VMS
  367.                     cp++; // vms, skip leading /
  368. #endif
  369. #ifdef OS_MAC
  370.                     cp++; // mac, skip leading /
  371. #endif
  372. #ifdef OS_DOS
  373.                     if (StrChr(cp,':')) cp++; // have "/C:\dos\path" form
  374.                     else *cp= '\\'; // have a "/dos\path" form
  375. #endif
  376. #endif
  377.                     }
  378.                 nob->fType= kTypeFile;  // !! need ftp folder handling !?
  379.                 nob->StorePath( cp);  
  380.                 break;
  381.  
  382.             case DNetOb::kHTTPprot:    // http://host.name:80/path/to/data
  383.                 nob->fType= kTypeHtml;  
  384.                 if (*cp == 0) nob->StorePath( "/");
  385.                 else nob->StorePath( cp);  
  386.                 break;
  387.  
  388.             case DNetOb::kTelnetprot:
  389.                 nob->fType= kTypeTelnet;  
  390.                 nob->StorePath( cp);  
  391.                 break;
  392.             case DNetOb::kTN3270prot:
  393.                 nob->fType= kTypeTn3270;  
  394.                 nob->StorePath( cp);  
  395.                 break;
  396.  
  397.             case DNetOb::kFingerprot:
  398.             case DNetOb::kWhoisprot:
  399.                 nob->fType= kTypeQuery;  
  400.                 nob->StorePath( cp);  
  401.                 break;
  402.             
  403.             case DNetOb::kWAISprot: // ?? or need Folder type or Waisdir & WaisDoc types?
  404.             default:
  405.                 nob->fType= kTypeFile;  
  406.                 nob->StorePath( cp);  
  407.                 break;
  408.             }
  409.             
  410.                 // set a usable title !?
  411.         const char *name= nob->GetPath();
  412.         if ( name == NULL || *name == 0 || StrCmp(name, "/") == 0) 
  413.             name= nob->GetHost();
  414.         else 
  415.             name= gFileManager->FilenameFromPath(name);
  416.         if ( name && *name != 0 ) 
  417.             nob->StoreName( (char*)name);  
  418.              
  419.         }
  420.     
  421.     MemFree( line);
  422.     return true;
  423. }
  424.